/********************************
 *  Seengreat 2.4 Inch LCD Display demo
 *  Author(s):Andy Li from Seengreat
 * ********************************/
 
#include <string.h>
#include <stdio.h>  

#include "lcd_2inch4.h"
         
//LCD pen color and background color   
uint16_t POINT_COLOR=0x0000; //brush color
uint16_t BACK_COLOR=0xFFFF;  //background color  
_lcd_dev lcddev;

void Lcd_Gpio_Init(void)
{
  pinMode(LCD_CS, OUTPUT);
  pinMode(LCD_RST, OUTPUT);
  pinMode(LCD_DC, OUTPUT);
  pinMode(LCD_BL, OUTPUT);
  pinMode(TP_CS, OUTPUT);
  pinMode(SD_CS, OUTPUT);
  pinMode(TEST_P, OUTPUT);
  TP_CS_1;
  SD_CS_1;

}

//Hardware reset
static void Lcd_Reset(void)
{
  //LCD reset
  LCD_RST_1;
  delay(1);
  LCD_RST_0;
  delay(80);
  LCD_RST_1;
  delay(10);
}

//value is in 0~255
void BlackLight_SetValue(uint16_t value)
{     
    if(value < 255)
    {   
       analogWrite(LCD_BL, value);
    }
}

//Write command
static void Spi_write_cmd(uint8_t data)  
{ 
   LCD_CS_0;
   LCD_DC_0;
   SPI.transfer(data);
   LCD_CS_1;
}
//Write a byte data
static void Spi_write_data(uint8_t data) 
{ 
   LCD_CS_0;
   LCD_DC_1;
   SPI.transfer(data);
   LCD_CS_1;
}  
//Write a word data
void Spi_write_word(uint16_t data)
{
  uint8_t temp;
  temp = (data >> 8) & 0xff; 
  SPI.transfer(temp);
  temp = data & 0xff;        
  SPI.transfer(temp);

}   

//Common register initialization
void Lcd_Init(void)
{
    Lcd_Reset();
    delay(120);
    Spi_write_cmd(0x01);
    delay(120);
    Spi_write_cmd(0x11);
    delay(120);
    Spi_write_cmd(0xCF);
    Spi_write_data(0x00);
    Spi_write_data(0xC1);
    Spi_write_data(0X30);
    Spi_write_cmd(0xED);
    Spi_write_data(0x64);
    Spi_write_data(0x03);
    Spi_write_data(0X12);
    Spi_write_data(0X81);
    Spi_write_cmd(0xE8);
    Spi_write_data(0x85);
    Spi_write_data(0x00);
    Spi_write_data(0x79);
    Spi_write_cmd(0xCB);
    Spi_write_data(0x39);
    Spi_write_data(0x2C);
    Spi_write_data(0x00);
    Spi_write_data(0x34);
    Spi_write_data(0x02);
    Spi_write_cmd(0xF7);
    Spi_write_data(0x20);
    Spi_write_cmd(0xEA);
    Spi_write_data(0x00);
    Spi_write_data(0x00);
    Spi_write_cmd(0xC0); //Power control
    Spi_write_data(0x1D); //VRH[5:0]
    Spi_write_cmd(0xC1); //Power control
    Spi_write_data(0x12); //SAP[2:0];BT[3:0]
    Spi_write_cmd(0xC5); //VCM control
    Spi_write_data(0x33);
    Spi_write_data(0x3F);
    Spi_write_cmd(0xC7); //VCM control
    Spi_write_data(0x92);
    Spi_write_cmd(0x3A); // Memory Access Control
    Spi_write_data(0x55);

    Spi_write_cmd(0x36); // Memory Access Control
    Spi_write_data(0x08);

    Spi_write_cmd(0xB1);
    Spi_write_data(0x00);
    Spi_write_data(0x12);
    Spi_write_cmd(0xB6); // Display Function Control
    Spi_write_data(0x0A);
    Spi_write_data(0xA2);

    Spi_write_cmd(0x44);
    Spi_write_data(0x02);

    Spi_write_cmd(0xF2); // 3Gamma Function Disable
    Spi_write_data(0x00);
    Spi_write_cmd(0x26); //Gamma curve selected
    Spi_write_data(0x01);
    Spi_write_cmd(0xE0); //Set Gamma
    Spi_write_data(0x0F);
    Spi_write_data(0x22);
    Spi_write_data(0x1C);
    Spi_write_data(0x1B);
    Spi_write_data(0x08);
    Spi_write_data(0x0F);
    Spi_write_data(0x48);
    Spi_write_data(0xB8);
    Spi_write_data(0x34);
    Spi_write_data(0x05);
    Spi_write_data(0x0C);
    Spi_write_data(0x09);
    Spi_write_data(0x0F);
    Spi_write_data(0x07);
    Spi_write_data(0x00);
    Spi_write_cmd(0XE1); //Set Gamma
    Spi_write_data(0x00);
    Spi_write_data(0x23);
    Spi_write_data(0x24);
    Spi_write_data(0x07);
    Spi_write_data(0x10);
    Spi_write_data(0x07);
    Spi_write_data(0x38);
    Spi_write_data(0x47);
    Spi_write_data(0x4B);
    Spi_write_data(0x0A);
    Spi_write_data(0x13);
    Spi_write_data(0x06);
    Spi_write_data(0x30);
    Spi_write_data(0x38);
    Spi_write_data(0x0F);
    Spi_write_cmd(0x11);
    delay(120);
    Spi_write_cmd(0x29); //Display on


    LCD_Display_Dir(DFT_SCAN_DIR); 
    BlackLight_SetValue(200);   //Turn on the backlight
    LCD_Clear(BACKGROUND_COLOR);
    Serial.println("LCD Finish Init"); 
//
}

//Set the auto scan direction of the LCD
//Note: Other functions may be affected by this function setting
//dir:0~7,Represents 8 directions (see lcd.h for specific definitions)      
void LCD_Scan_Dir(uint8_t dir)
{
  uint16_t regval=0;
  switch(dir)
  {
    case L2R_U2D://left to right, up to down
      regval = (0<<7)|(0<<6)|(0<<5);
      break;
    case L2R_D2U://left to right, from down to up
      regval|=(1<<7)|(0<<6)|(0<<5); 
      break;
    case R2L_U2D://right to left, up to down
      regval|=(0<<7)|(1<<6)|(0<<5); 
      break;
    case R2L_D2U://right to left,down to up
      regval|=(1<<7)|(1<<6)|(0<<5); 
      break;   
    case U2D_L2R://up to down,left to right
      regval|=(0<<7)|(0<<6)|(1<<5); 
      break;
    case U2D_R2L://up to down,right to left
      regval|=(1<<7)|(0<<6)|(1<<5);  
      break;
    case D2U_L2R://down to up,left to right
      regval|=(0<<7)|(1<<6)|(1<<5);
      break;
    case D2U_R2L://down to up,right to left
      regval|=(1<<7)|(1<<6)|(1<<5); 
      break;   
  }
  regval|=0x08; 
  Spi_write_cmd(0x36); 
  Spi_write_data(regval);   
}

//Set the LCD display direction
//dir:vertical screen or horizontal screen
void LCD_Display_Dir(uint8_t dir)
{
   if(dir==0 || dir==1 || dir==2 || dir==3)//vertical screen
   {
      lcddev.dir=0;
      lcddev.width=LCD_H;
      lcddev.height=LCD_W;

      lcddev.wramcmd=0X2C;
      lcddev.setxcmd=0X2A;
      lcddev.setycmd=0X2B;  
   }
   else         //horizontal screen
   {           
      lcddev.dir=1; 
      lcddev.width=LCD_W;
      lcddev.height=LCD_H;

      lcddev.wramcmd=0X2C;
      lcddev.setxcmd=0X2A;
      lcddev.setycmd=0X2B;      
   } 
   LCD_Scan_Dir(dir); //default LCD display direction
}

//select the srceen area(from point(start_x,start_y) to point(end_x,end_y))
void Set_Window(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t  end_y)
{ 
  Spi_write_cmd(0x2a);
  Spi_write_data(start_x >>8);
  Spi_write_data(start_x & 0xff);
  Spi_write_data((end_x-1) >> 8);
  Spi_write_data((end_x-1) & 0xff);

  Spi_write_cmd(0x2b);
  Spi_write_data(start_y >>8);
  Spi_write_data(start_y & 0xff);
  Spi_write_data((end_y-1) >> 8);
  Spi_write_data((end_y-1) & 0xff);

  Spi_write_cmd(0x2C);
}


//set cursor to the point(x, y)
void LCD_Set_Cursor(uint16_t x, uint16_t y)
{ 
   Set_Window(x, y, x, y);
}
//
//clear screen function
//color:fill color to clear
void LCD_Clear(uint16_t color)
{
  uint32_t i; 

  LCD_Set_Cursor(0x00,0x0000); //set cursor position
  Spi_write_cmd(lcddev.wramcmd);//Start writing to GRAM 
  LCD_CS_0;
  LCD_DC_1;      
  for(i=0;i<(uint32_t)LCD_W*LCD_H;i++)
  {
     Spi_write_word(color); 
  }
  LCD_CS_1;
}

void LCD_Clearx(void)
{
  uint32_t i=0;      

  LCD_Set_Cursor(0,0x0000); //set cursor position
  Spi_write_cmd(lcddev.wramcmd);//Start writing to GRAM 
  LCD_CS_0;
  LCD_DC_1;     
  for(i=0;i<25600;i++)
  {
    Spi_write_word(RED);    
  }
  for(;i<51200;i++)
  { 
    Spi_write_word(GREEN);     
  }
  for(;i<76800;i++)
  {
    Spi_write_word(BLUE);      
  }
  LCD_CS_1;
}

void Gui_fill_color(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    uint16_t i,temp=0;
    if(x1>x2)
    {
       temp = x1;
       x1 = x2;
       x2 = temp;
    }
    if(y1>y2)
    {
       temp = y1;
       y1 = y2;
       y2 = temp;
    }
    Set_Window(x1, y1, x2, y2);
    Spi_write_cmd(lcddev.wramcmd);//Start writing to GRAM 
    LCD_CS_0;
    LCD_DC_1;      
    for(i=0; i<(x2-x1)*(y2-y1); i++)
    {
       Spi_write_word(color); 
    }
    LCD_CS_1;
}

//set the point(x,y) to color
void Draw_Point(uint16_t x, uint16_t y, uint16_t color)
{
   LCD_Set_Cursor(x, y);
   Spi_write_cmd(lcddev.wramcmd);
   LCD_CS_0;
   LCD_DC_1;
   Spi_write_word(color); 
   LCD_CS_1;  
}
